package cn.ppool.xmlmapper.builder.parse.model.base;


import cn.ppool.xmlmapper.builder.MapperBuilder;
import cn.ppool.xmlmapper.builder.parse.model.func.CommentBO;
import cn.ppool.xmlmapper.builder.parse.model.func.IfBO;
import cn.ppool.xmlmapper.builder.parse.model.func.StringBO;
import cn.ppool.xmlmapper.builder.parse.model.func.WhereBO;
import cn.ppool.xmlmapper.builder.xml.XNode;
import cn.ppool.xmlmapper.exctption.NotDefineSymbolException;
import cn.ppool.xmlmapper.exctption.ScriptException;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;
import org.w3c.dom.NodeList;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Log4j2
public abstract class BaseBo {
    /**
     * 建造模型
     */
    public abstract void buildEntityModel();

    protected ScriptEngineManager engineManager;

    @Getter
    private final MapperBuilder mapperBuilder;
    @Getter
    protected Date initTime;

    public BaseBo(MapperBuilder mapperBuilder) {
        this.initTime = new Date();
        this.mapperBuilder = mapperBuilder;
        engineManager = new ScriptEngineManager();
    }


    public String cleanWhiteSpace(String str) {
        str = str.replaceAll("\r", "");
        String reStr = "";
        for (String line : str.split("\n")) {
            if (!line.replaceAll(" ", "").equals("")) {
                reStr = reStr.concat(line).concat("\n");
            }
        }
        return reStr;
    }


    protected List<BaseFuncBO> buildModel(final MapperBuilder configure, final XNode parentNode, final XNode currentNode) {
        List<BaseFuncBO> body = new ArrayList<>();
        if (currentNode == null) return body;
        NodeList nodeList = currentNode.getNode().getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            XNode childNode = currentNode.newXNode(nodeList.item(i));
            BaseFuncBO bo;
            switch (childNode.getName().toUpperCase()) {
                case WhereBO.TAG_NAME:
                    bo = new WhereBO(configure, parentNode, childNode);
                    break;
                case IfBO.TAG_NAME:
                    bo = new IfBO(configure, parentNode, childNode);
                    break;
                case CommentBO.TAG_NAME:
                    continue;
                default:
//                    if (getContent(null,null).length() == 0) continue;   // 判断是不是空白的
                    bo = new StringBO(configure, parentNode, childNode);
                    break;
            }
            bo.buildEntityModel();
            body.add(bo);
        }
        return body;
    }

    private Object scriptEval(String varName, Map<String, Object> allVar) {
        ScriptEngine engine = engineManager.getEngineByName("JavaScript");
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            engine.eval(mapperBuilder.getCustomerJavascriptFunction());
            for (Map.Entry<String, Object> val : allVar.entrySet()) {
                if (val.getValue() instanceof Date) {
                    engine.eval(MessageFormat.format("var {0}=new Date(''{1}'')", val.getKey(), sdf.format(val.getValue())));
                } else {
                    engine.put(val.getKey(), val.getValue());
                }
            }
            return engine.eval(varName);
        } catch (Exception e) {
            throw new ScriptException("script error:" + e.getMessage());
        }
    }


    protected String parseVariable(String str, Map<String, Object> allVar, Map<String, Object> sqlVar) {
        StringBuilder sql = new StringBuilder();
        int appendIndex = 0;
        int scanIndex = 0;
        Integer varIndex = 0;
        while (scanIndex < str.length()) {
            int shareBeginIndex = str.indexOf("{", scanIndex);
            //
            if (shareBeginIndex > 0) {
                String preChar = String.valueOf(str.charAt(shareBeginIndex - 1));
                if (":".equals(preChar) || "#".equals(preChar)) {
                    sql.append(str.substring(appendIndex, shareBeginIndex - 1));
                    int shareEndIndex = str.indexOf("}", shareBeginIndex);
                    if (shareEndIndex == -1) throw new RuntimeException("缺少}");
                    String varName = str.substring(shareBeginIndex + 1, shareEndIndex);
                    //
                    if (":".equals(preChar)) {                                                                      // :
                        if (varName.contains("(") && varName.contains(")")) {
                            Object scriptResult = scriptEval(varName, allVar);
                            //
                            String newVarName = "t" + String.valueOf(new Date().getTime()).concat("_").concat((varIndex++).toString());
                            sql.append(":").append(newVarName);
                            sqlVar.put(newVarName, scriptResult);
                        } else {
                            sql.append(":").append(varName);
                            sqlVar.put(varName, allVar.get(varName));
                        }
                    } else if ("#".equals(preChar)) {                                                                                    // #
                        if (varName.contains("(") && varName.contains(")")) {
                            Object scriptResult = scriptEval(varName, allVar);
                            sql.append(scriptResult);
                        } else {
                            sql.append(allVar.get(varName).toString());
                        }
                    } else {
                        throw new NotDefineSymbolException("未定义符号:" + preChar);
                    }
                    appendIndex = shareEndIndex + 1;
                    scanIndex = shareEndIndex + 1;
                } else {
                    scanIndex = shareBeginIndex + 1;
                }
            } else {
                sql.append(str.substring(appendIndex));
                break;
            }
        }
        return sql.toString();
    }


}
